package com.ruoyi.frame.spring.intercept;

import com.ruoyi.frame.base.constant.FieldConstant;
import com.ruoyi.frame.util.TraceIdUtil;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * slf4j.MDC全链路日志追踪
 * 拦截器和过滤器不同的是拦截器可以知道当前的用户请求的是哪个控制器的哪个方法
 * 单单使用@Component是不能让拦截器起作用的，还需要额外的配置
 * （在WebConfig里面配置 1、继承WebMvcConfigurerAdapter  2、在addInterceptors里面添加拦截器）
 * 其实我们知道了是哪个控制器的哪个方法被调用也是没用的，因为我们不知道用户请求过来的参数是什么　<br> * 如果需要知道请求参数的话需要用到切片Aspect（也就是Spring AOP）
 *
 * @author zengXiangJiang
 * @version 1.0.0
 */
@Slf4j
@Component
public class LogHandlerInterceptor implements HandlerInterceptor {

    /**
     * 控制器方法被调用之前
     *
     * @param request  HttpServletRequest
     * @param response HttpServletResponse
     * @param handler  Object
     * @return 返回false就不会调用后面的方法了
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        log.debug("============ preHandle Start ============");
        //如果有上层调用就用上层的ID
        String traceId = request.getHeader(FieldConstant.TRACE_ID);
        if (traceId == null) {
            traceId = TraceIdUtil.getTraceId();
        }
        MDC.put(FieldConstant.TRACE_ID, traceId);
        log.trace("traceId: {}", traceId);

        // 打印请求 url, Http method, 调用 controller 的全路径以及执行方法, 请求的 IP, 请求入参//类方法
        String requestMethod = request.getMethod();
        String contentType = request.getContentType();
        String requestUrl = request.getRequestURL().toString();
        log.info("requestUrl    : {}", requestUrl);
        log.info("HTTP Method   : {}", requestMethod);
        log.info("contentType   : {}", contentType);
        log.info("IP            : {}", request.getRemoteAddr());

        return true;
    }

    /**
     * 控制器的方法处理之后 如果出现异常则不调用
     *
     * @param request      /
     * @param response     /
     * @param handler      /
     * @param modelAndView /
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
        log.trace("------ doAfter ------");
    }

    /**
     * 出不出现异常都会调用
     *
     * @param request  /
     * @param response /
     * @param handler  /
     * @param ex       /
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        //调用结束后
        // 移除当前线程的键值
        TraceIdUtil.removeTraceId();
        // 换行，方便分割查看
        log.debug("============ afterCompletion End ============ {}", System.lineSeparator());
        // 删除MDC中的traceId
        MDC.remove(FieldConstant.TRACE_ID);
    }
}
